package com.thinkit.utils.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.io.CharStreams;
import com.thinkit.utils.enums.BelongEnum;
import com.thinkit.utils.enums.InputTypeEnum;
import com.thinkit.utils.iterator.BeanPropertyBox;
import com.thinkit.utils.iterator.BeanPropertyIterator;
import com.thinkit.utils.iterator.ThinkIterator;
import com.thinkit.utils.model.BaseDto;
import com.thinkit.utils.model.BaseFieldDto;
import com.thinkit.utils.model.DynamicModel;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

public class ModelFieldUtil {


    private static final String cover = "cover";

    private static final String data = "data";

    public static List<DynamicModel> jsonStrToModel(String jsonStr){
       if(Checker.BeNotBlank(jsonStr)){
            List<DynamicModel> dynamicModels=toList(jsonStr,DynamicModel.class);
            if(Checker.BeNotEmpty(dynamicModels)){
                Collections.sort(dynamicModels);
            }
            return dynamicModels;
       }
       return Lists.newArrayList();
    }

    public static Map<String,Object> jsonStrToMap(String jsonStr,Map<String,Object> params){
        if(null==params){
            params = new HashMap<>();
        }
        if(Checker.BeNotBlank(jsonStr)){
            List<DynamicModel> dynamicModels=jsonStrToModel(jsonStr);
            if(Checker.BeNotEmpty(dynamicModels)){
                for(DynamicModel dynamicModel:dynamicModels){
                    if(dynamicModel.getIsExtend()){
                        params.put(dynamicModel.getFieldCode(),dynamicModel.getDefaultValue());
                    }
                }
            }
        }
        return params;
    }

    public static Map<String,Object> jsonStrToMap(String jsonStr){
        return jsonStrToMap(jsonStr,null);
    }

    public static List<DynamicModel> listExtendModel(String jsonStr){
        List<DynamicModel>  extendFields= jsonStrToModel(jsonStr);
        if(Checker.BeNotEmpty(extendFields)){
            return  extendFields.stream()
                    .filter(field -> field.getIsExtend())
                    .collect(Collectors.toList());
        }
        return Lists.newArrayList();
    }

    public static void setFieldVal(List<DynamicModel>  modelFields, BaseDto baseDto, boolean setField){
       if(Checker.BeNotEmpty(modelFields)){
           BeanPropertyBox propertyBox=new BeanPropertyBox(baseDto);
           ThinkIterator iterator=propertyBox.iterator(BeanPropertyIterator.class);
           while(iterator.hasNext()){
               Field field = (Field)iterator.next();
               if(Checker.BeNotNull(field)){
                   for(DynamicModel modelField:modelFields){
                       if(field.getName().equals(modelField.getFieldCode())){
                           try {
                               if(setField){
                                   modelField.setDefaultValue(field.get(baseDto));
                               }else{
                                   field.set(baseDto,modelField.getDefaultValue());
                               }
                           } catch (IllegalAccessException e) {
                               e.printStackTrace();
                           }
                       }
                   }
               }
           }
       }
    }

    public static void setFieldVal(BaseDto baseDto, Map map){
        if(Checker.BeNotNull(baseDto) && Checker.BeNotNull(map)){
            List<Field> fields = Arrays.asList(baseDto.getClass().getDeclaredFields());
            if(Checker.BeNotEmpty(fields)){
                for( Field field:fields){
                    field.setAccessible(true);
                    boolean hasValue = map.containsKey(field.getName()) && Checker.BeNotNull(map.get(field.getName()));
                    if(hasValue){
                        try {
                            field.set(baseDto,map.get(field.getName()));
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }



    public static List<DynamicModel> listDefaultModel(String jsonStr){
        List<DynamicModel>  defaultFields= jsonStrToModel(jsonStr);
        if(Checker.BeNotEmpty(defaultFields)){
          return  defaultFields.stream()
                  .filter(field -> !field.getIsExtend())
                  .collect(Collectors.toList());

        }
        return Lists.newArrayList();
    }


    public static  String modelToJsonStr (List<DynamicModel> dynamicModel){
        if(Checker.BeNotEmpty(dynamicModel)){
            return toJsonStr(dynamicModel);
        }
        return null;
    }

    public static void copyField (List<DynamicModel> dest, List<DynamicModel> src){
        if(Checker.BeNotEmpty(src)){ // src to dest
            for(DynamicModel d:dest){
                for(DynamicModel s:src){
                   if(d.getFieldCode().equals(s.getFieldCode()) && d.getInputType().equals(s.getInputType())){
                       d.setDefaultValue(s.getDefaultValue());
                       continue;
                   }
                }
            }
        }
    }


    public static void filterMapToSetFieldValue (List<DynamicModel> dynamicModels,Map<String,Object> params){
        if(Checker.BeNotEmpty(dynamicModels)  && params!=null  && !params.isEmpty()){
            for(DynamicModel dynamicModel:dynamicModels){
                String code = dynamicModel.getFieldCode();
                if(params.containsKey(code)){
                    dynamicModel.setDefaultValue(params.get(code));
                }
            }
        }
    }


    public static List<DynamicModel> loadModel(BelongEnum belongEnum){
        List<DynamicModel>  modelList =loadModel();
        if(Checker.BeNotEmpty(modelList)){
            modelList=  modelList.stream().filter(s->s.getBelong().contains(belongEnum.getCode())).collect(Collectors.toList());
        }
        return modelList;
    }


    public static List<DynamicModel> loadModel(){
        Resource resource = new ClassPathResource("model.json");
        if(resource.exists()){
            try {
                InputStream inputStream = resource.getInputStream();
                //String jsonStr = FileUtil.readString(resource.getFile(),Charset.forName("UTF-8"));
                String jsonStr = CharStreams.toString(new InputStreamReader(inputStream, Charsets.UTF_8));
                List<DynamicModel> models = toList(jsonStr,DynamicModel.class);
                return Checker.BeNotEmpty(models)?models: Lists.newArrayList();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Lists.newArrayList();
    }

    public static void filter(BaseFieldDto v){
        List<DynamicModel> defaultlFields= toList(v.getDefaultFieldList(), DynamicModel.class);
        List<DynamicModel> extendField = toList(v.getExtendFieldList(),DynamicModel.class);
        extendFilter(extendField);
        List<DynamicModel> allField  = new ArrayList<>();
        allField.addAll(extendField);
        if(Checker.BeNotEmpty(defaultlFields)){
            Map<String,String> fieldTextMap =new HashMap<>(16);
            List<String> requireFied= new ArrayList<>();
            for(DynamicModel modelDto:defaultlFields){
                fieldTextMap.put(modelDto.getFieldCode(),modelDto.getFieldAliase());
                if(modelDto.getIsRequired()){
                    requireFied.add(modelDto.getFieldCode());
                }
                if(modelDto.getCheck()){
                    allField.add(modelDto);
                }
            }
            v.setFieldTextMap(toJsonStr(fieldTextMap)).setRequiredFieldList(toJsonStr(requireFied)).
            setAllFieldList(toJsonStr(allField));
        }
    }

    private static void extendFilter(List<DynamicModel> extendFields){
        if(Checker.BeNotEmpty(extendFields)){
            for(DynamicModel dynamicModel:extendFields){
                dynamicModel.setFieldAliase(dynamicModel.getFieldName());
            }
        }
    }


    private static <T> List<T> toList(String jsonStr,Class<T> tClass){
        List<T> models = JSONUtil.toList(JSONUtil.parseArray(jsonStr),tClass);
        return models;
    }

    private static String toJsonStr(Object object){
        return JSONUtil.toJsonStr(object);
    }

    public static void formatCover(Map<String, Object> map,boolean getFrist) {
        if(map!=null && !map.isEmpty()){
            if(map.containsKey(cover) && Checker.BeNotNull(map.get(cover))){
                List<Map> covers = toList(map.get(cover).toString(),Map.class);
                if(getFrist){
                    map.put(cover,Checker.BeNotEmpty(covers)?covers.get(0):null);
                }else{
                    map.put(cover,covers);
                }
            }
        }
    }

    public static void formatCovers(List<Map<String, List>> maps, boolean getFrist) {
        if(Checker.BeNotEmpty(maps)){
            for(Map map:maps){
                formatCover(map,getFrist);
            }
        }
    }

    public static void formatData(Map<String, Object> map) {
        if(map!=null && !map.isEmpty()){
            if(map.containsKey(data) && Checker.BeNotNull(map.get(data))){
                List<DynamicModel> dynamicModels=jsonStrToModel(map.get(data).toString());
                replaceMap(dynamicModels,map);
            }
        }
    }

    public static void formatDatas(List<Map<String, Object>> maps) {
        if(Checker.BeNotEmpty(maps)){
            for(Map map:maps){
                formatData(map,true);
            }
        }
    }

    public static void formatData(Map<String, Object> map,boolean filterCover) {
        formatData(map);
        if(filterCover && Checker.BeNotEmpty(map)){
            Object coverObj = map.get(cover);
            if(map.containsKey(cover) && Checker.BeNotNull(coverObj)){
                List<Map> covers = toList(coverObj.toString(),Map.class);
                map.put(cover,Checker.BeNotEmpty(covers)?covers.get(0):null);
            }
        }
    }

    private static void replaceMap(List<DynamicModel> dynamicModels,Map<String, Object> map){
        boolean isReplace = Checker.BeNotEmpty(dynamicModels) && map!=null && !map.isEmpty();
         if(isReplace){
             for(DynamicModel dynamicModel:dynamicModels){
                 String inputType = dynamicModel.getInputType();
                 Object defaultValue= dynamicModel.getDefaultValue();
                 String fieldCode = dynamicModel.getFieldCode();
                 boolean isPicture = InputTypeEnum.INPUT_PICTURE.getCode().equals(inputType);
                 boolean isTag = InputTypeEnum.INPUT_TAG.getCode().equals(inputType);
                 if(isPicture){
                     if(Checker.BeNotNull(defaultValue) && Checker.BeNotBlank(defaultValue.toString())){
                         List<Map> covers = toList(defaultValue.toString(),Map.class);
                         map.put(fieldCode,Checker.BeNotEmpty(covers)?covers.get(0):null);
                     }
                 }else if(isTag ){
                     if(Checker.BeNotNull(defaultValue) && Checker.BeNotBlank(defaultValue.toString())){
                         List<String> tags = Arrays.asList(defaultValue.toString().split(","));
                         map.put(fieldCode,tags);
                     }
                 }else{
                     map.put(fieldCode,defaultValue);
                 }

             }
         }
    }
}
